home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / PASCAL / ALLSWAGS.ZIP / SWAGG-M.ZIP / MISC.SWG / 0161_Reading DOOM WAD Files.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-09-04  |  9.2 KB  |  396 lines

  1.  
  2. {
  3. >does anyone know the file format for a doom wad in pascal? This would
  4. >really be helpful for me. Thanx a lot.
  5. I bet you really wanted a few pages of mostly uncommented source code, right?
  6. And not just that, but it's pretty poorly written too :)
  7.  
  8. }
  9. Program WADRead;
  10. {$M 65520, 0, 0}
  11.  
  12. {Interface}
  13.  
  14. Uses DOS, Crt, Strings, Mode13h;  { unit MODE13H at end of snipet }
  15.  
  16. Type
  17.   String8 = String [8];
  18.   TWAD_Type = (Internal, Patch);
  19.   StringZ8 = Array [1..8] Of Char;
  20.  
  21.   TRawPalette = Array [1..768] Of Byte;
  22.   PRawPalette = ^TRawPalette;
  23.  
  24. Const
  25. TWAD_TypeString: Array [1..2] Of String [4] = ('IWAD', 'PWAD');
  26.  
  27. Var
  28. WAD_File: File;
  29.   WAD_Name: String;
  30.   WAD_Type: TWAD_Type;
  31.   WAD_NumEntries, WAD_DirectoryPointer: LongInt;
  32.   RawTexture: Array [1..32767] Of Byte;
  33.   RawPalette: Array [1..768 * 14] Of Byte;
  34.  
  35. {Implementation}
  36.  
  37. {Add a backslash to the end of a directory name}
  38. {From my TTString unit, part of my TurboTools library}
  39. Function TT_AddSlash (S : String) : String;
  40. Var
  41.   L : Byte Absolute S;
  42.  
  43. Begin
  44.   If (L > 0) And (S [L] <> '\') Then
  45.   Begin
  46.     Inc (L);
  47.     S [L] := '\';
  48.   End;
  49.   TT_AddSlash := S;
  50. End;
  51.  
  52. {Fill out string with spaces}
  53. {From TTString}
  54. Function TT_PadString (S: String; L: Integer) : String;
  55. Var
  56.   I: Integer;
  57.  
  58. Begin
  59.   For I := Length (S) + 1 To L Do
  60.     S [I] := #32;
  61.   S [0] := Chr (L);
  62.   TT_PadString := S;
  63. End;
  64.  
  65.  
  66. {Open the specified WAD file}
  67. {If FileName = '' then try DOOM.WAD, DOOM2.WAD, then search}
  68. {for the first WAD in the directory}
  69. Function WAD_Open (FileName: String): Boolean;
  70. Function WAD_OpenFile: Boolean;
  71. Var
  72. FileFound: SearchRec;
  73.  
  74. Begin
  75. If Length (FileName) = 0 Then Begin
  76.   {User hasn't specified a file name, open in the current directory}
  77.  
  78.     {Try to open DOOM.WAD in the current directory}
  79.     Assign (WAD_File, 'DOOM.WAD');
  80.     {$I-}
  81.     Reset (WAD_File, 1);
  82.     {$I+}
  83.     If IOResult = 0 Then Begin
  84.     {Succesfully opened DOOM.WAD}
  85.       GetDir (0, WAD_Name);
  86.       WAD_Name := TT_AddSlash (WAD_Name) + 'DOOM.WAD';
  87.       WAD_OpenFile := True;
  88.       Exit;
  89.     End;
  90.  
  91.     {Couldn't open DOOM.WAD, try DOOM2.WAD}
  92.     Assign (WAD_File, 'DOOM2.WAD');
  93.     {$I-}
  94.     Reset (WAD_File, 1);
  95.     {$I+}
  96.     If IOResult = 0 Then Begin
  97.     {Succesfully opened DOOM2.WAD}
  98.       GetDir (0, WAD_Name);
  99.       WAD_Name := TT_AddSlash (WAD_Name) + 'DOOM2.WAD';
  100.       WAD_OpenFile := True;
  101.       Exit;
  102.     End;
  103.  
  104.     {Couldn't open DOOM2.WAD, try opening the first WAD we find}
  105.     FindFirst ('*.WAD', AnyFile, FileFound);
  106.     If DOSError = 0 Then Begin
  107.     {Found a WAD file}
  108.       GetDir (0, WAD_Name);
  109.       WAD_Name := TT_AddSlash (WAD_Name) + FileFound. Name;
  110.       Assign (WAD_File, WAD_Name);
  111.       {$I-}
  112.       Reset (WAD_File, 1);
  113.       {$I+}
  114.       WAD_OpenFile := (IOResult = 0);
  115.       Exit;
  116.     End;
  117.  
  118.     {Couldn't open or find any WADs}
  119.     WAD_OpenFile := False;
  120.     Exit;
  121.   End Else Begin
  122.   {User specified a WAD file name}
  123.     Assign (WAD_File, FileName);
  124.     {$I-}
  125.     Reset (WAD_File, 1);
  126.     {$I+}
  127.     If IOResult = 0 Then Begin
  128.     {Succesfully opened specified WAD file}
  129.       WAD_Name := FExpand (FileName);
  130.       WAD_OpenFile := True;
  131.       Exit;
  132.     End;
  133.  
  134.     {Unable to open specified WAD file}
  135.     WAD_OpenFile := False;
  136.   End;
  137. End;
  138.  
  139. Var
  140. IDString: Array [1..4] Of Char;
  141.  
  142. Begin
  143.   If WAD_OpenFile Then Begin
  144.     {Check the first 4 byte to determine WAD type (and if it's valid)}
  145.   BlockRead (WAD_File, IDString, 4);
  146.     If IDString = TWAD_TypeString [1] Then
  147.     WAD_Type := Internal
  148.     Else If IDString = TWAD_TypeString [2] Then
  149.     WAD_Type := Patch
  150.     Else Begin
  151.     WAD_Open := False;
  152.       Exit;
  153.     End;
  154.     {Read in the other header data, number of entries and the pointer to}
  155.     {the directory at the end of the file}
  156.     BlockRead (WAD_File, WAD_NumEntries, 4);
  157.     BlockRead (WAD_File, WAD_DirectoryPointer, 4);
  158.   End Else
  159.   WAD_Open := False;
  160. End;
  161.  
  162. {Read in directory entry EntryNum (0 based)}
  163. Function WAD_ReadEntry (EntryNum: LongInt; var Start, Length: LongInt; var Ent
  164. Var
  165. EntryNameZ: StringZ8;
  166.  
  167. Begin
  168.   {$I-}
  169. Seek (WAD_File, WAD_DirectoryPointer + (EntryNum * 16));
  170.   {$I+}
  171.   If IOResult = 0 Then Begin
  172.   BlockRead (WAD_File, Start, 4);
  173.   BlockRead (WAD_File, Length, 4);
  174.   BlockRead (WAD_File, EntryNameZ, 8);
  175.   EntryName := StrPas (@EntryNameZ);
  176.     WAD_ReadEntry := True;
  177.   End Else
  178.     WAD_ReadEntry := False;
  179. End;
  180.  
  181. {Search for directory entry with name EntryName (case sensitive)}
  182. Function WAD_FindEntry (EntryName: String8): LongInt;
  183. Var
  184. EntryNum, Start, Length: LongInt;
  185.   CurEntryName: String8;
  186.  
  187. Begin
  188. For EntryNum := 0 To WAD_NumEntries - 1 Do
  189.   If Not WAD_ReadEntry (EntryNum, Start, Length, CurEntryName) Then Begin
  190.     WAD_FindEntry := -2;
  191.       Exit;
  192.     End Else
  193.     If CurEntryName = EntryName Then Begin
  194.       WAD_FindEntry := EntryNum;
  195.         Exit;
  196.       End;
  197.   WAD_FindEntry := -1;
  198. End;
  199.  
  200. {Read in the data for a directory entry.  Use WAD_ReadEntry first}
  201. Function WAD_ReadEntryData (Start, Length: LongInt; Data: Pointer): Boolean;
  202. Begin
  203.   {$I-}
  204. Seek (WAD_File, Start);
  205.   BlockRead (WAD_File, Data^, Length);
  206.   {$I+}
  207.   WAD_ReadEntryData := (IOResult = 0);
  208. End;
  209.  
  210. Procedure WAD_DisplayTile (RawTexture: Array of Byte);
  211. Var
  212. Line: Byte;
  213.  
  214. Begin
  215.   For Line := 0 To 63 Do
  216.   Move (RawTexture [Line * 64], Mem [$A000:Line * 320], 64);
  217. {  Repeat Until KeyPressed;
  218.   TextMode (LastMode);}
  219. End;
  220.  
  221. Procedure WAD_SetPalette (RawPalette: PRawPalette); {[1..768]}
  222. Var
  223. Color: Byte;
  224.  
  225. Begin
  226. For Color := 0 To 255 Do
  227.     Mode13h. SetCol (Color, RawPalette^ [Color * 3 + 1] div 4 ,
  228. RawPalette^ [Color * 3 + 2] div 4,
  229. RawPalette^ [Color * 3 + 3] div 4);
  230. End;
  231.  
  232. Procedure WAD_DisplaySprite (RawSprite: Array of Byte);
  233. Var
  234. Width, Height, Left, Top, X, Y, Column: Word;
  235.   ColumnOffset, PixelOffset: LongInt;
  236.   Pixel, Count: Byte;
  237.  
  238. Begin
  239. Move (RawSprite [0], Width, 2);
  240.   Move (RawSprite [2], Height, 2);
  241.   Move (RawSprite [4], Left, 2);
  242.   Move (RawSprite [6], Top, 2);
  243.   For Column := 1 To Width Do Begin
  244.     X := Column - 1;
  245.   Move (RawSprite [4 + Column * 4], ColumnOffset, 4);
  246.  
  247.     Repeat
  248.     {for each post}
  249.       If Not (RawSprite [ColumnOffset] = $FF) Then Begin
  250.     Y := RawSprite [ColumnOffset];
  251.       Count := RawSprite [ColumnOffset + 1];
  252.       For PixelOffset := ColumnOffset + 3 To ColumnOffset + Count + 2 Do Begi
  253.         Inc (Y);
  254.         PlotPixel (X, Y, RawSprite [PixelOffset]);
  255.       End;
  256.       ColumnOffset := ColumnOffset + Count + 4;
  257.       End;
  258.     Until RawSprite [ColumnOffset] = $FF;
  259.   End;
  260. End;
  261.  
  262. Var
  263. Entry, Start, Length: LongInt;
  264.   Success: Boolean;
  265.   EntryName, WhichEntry: String8;
  266.  
  267. Begin
  268.   ClrScr;
  269.   WriteLn ('Enter path to WAD file');
  270.   Write (': ');
  271.   ReadLn (WAD_Name);
  272.  
  273.   Success := WAD_Open (WAD_Name);
  274.   If Not Success Then Begin
  275.   WriteLn ('Unable to open ' + WAD_Name);
  276.     Halt;
  277.   End;
  278.  
  279.   WriteLn ('Opened: ', WAD_Name);
  280.   WriteLn ('Wad type: ', Ord (WAD_Type));
  281.   WriteLn ('Num entries: ', WAD_NumEntries);
  282.   WriteLn ('Pointer to Directory: ', WAD_DirectoryPointer);
  283.  
  284.   WriteLn;
  285.   WriteLn ('Press any key to continue...');
  286.   Repeat Until KeyPressed;
  287.   ReadKey;
  288.  
  289.   WriteLn;
  290.   WriteLn ('Directory Entries: ');
  291.   For Entry := 0 To WAD_NumEntries - 1 Do Begin
  292.     WAD_ReadEntry (Entry, Start, Length, EntryName);
  293.   Write (TT_PadString (EntryName, 10));
  294.   End;
  295.  
  296.   WriteLn ('Display which title?');
  297.   Write (': ');
  298.   ReadLn (WhichEntry);
  299.   If WhichEntry = '' Then
  300.   Halt;
  301.  
  302. Mode13h.Init;
  303.   WAD_ReadEntry (WAD_FindEntry ('PLAYPAL'), Start, Length, EntryName);
  304.   WAD_ReadEntryData (Start, Length, @RawPalette);
  305.   WAD_ReadEntry (WAD_FindEntry (WhichEntry), Start, Length, EntryName);
  306.   WAD_ReadEntryData (Start, Length, @RawTexture);
  307.   WAD_SetPalette (@RawPalette [6145]);
  308. {  WAD_DisplayTile (RawTexture);}
  309.   WAD_DisplaySprite (RawTexture);
  310.   For Entry := 8 DownTo 0 Do Begin
  311.     Mode13h. WaitRetrace;
  312. WAD_SetPalette (@RawPalette [768 * Entry+ 1]);
  313.     Delay (20);
  314.  
  315.   End;
  316.   Repeat Until KeyPressed;
  317.   TextMode (LastMode);
  318. End.
  319. ***
  320.  
  321. Now you need my boring Mode13h unit:
  322.  
  323. *** C:\TP\WORK\MODE13H.PAS
  324. Unit Mode13h;
  325.  
  326. Interface
  327.  
  328. Procedure GetCol(C : Byte; Var R, G, B : Byte);
  329. Procedure SetCol(C, R, G, B : Byte);
  330. Procedure Init;
  331. Procedure PlotPixel (X, Y: Word; Color: Byte);
  332. Procedure WaitRetrace;
  333.  
  334. Implementation
  335.  
  336. Const PelAddrRgR  = $3C7;
  337.       PelAddrRgW  = $3C8;
  338.       PelDataReg  = $3C9;
  339.  
  340. Procedure GetCol(C : Byte; Var R, G, B : Byte);
  341. Begin
  342.    Port[PelAddrRgR] := C;
  343.    R := Port[PelDataReg];
  344.    G := Port[PelDataReg];
  345.    B := Port[PelDataReg];
  346. End;
  347.  
  348. Procedure SetCol(C, R, G, B : Byte);
  349. Begin
  350.    Port[PelAddrRgW] := C;
  351.    Port[PelDataReg] := R;
  352.    Port[PelDataReg] := G;
  353.    Port[PelDataReg] := B;
  354. End;
  355.  
  356. Procedure Init; Assembler;
  357. Asm
  358. mov ax, 13h
  359.   int 10h
  360. End;
  361.  
  362. Procedure PlotPixel (X, Y: Word; Color: Byte); Assembler;
  363. Asm
  364. push es
  365.   push di
  366.   mov ax, Y
  367.   mov bx, ax
  368.   shl ax, 8
  369.   shl bx, 6
  370.   add ax, bx
  371.   add ax, X
  372.   mov di, ax
  373.   mov ax, 0A000h
  374.   mov es, ax
  375.   mov al, Color
  376.   mov es:[di], al
  377.   pop di
  378.   pop es
  379. End;
  380.  
  381. Procedure WaitRetrace; Assembler;
  382. Asm;
  383.   mov     dx, 03DAh
  384. @@WaitRetrace_LoopA:
  385.   in      al, dx
  386.   and     al, 08h
  387.   jnz     @@WaitRetrace_LoopA
  388. @@WaitRetrace_LoopB:
  389.   in      al, dx
  390.   and     al, 08h
  391.   jz      @@WaitRetrace_LoopB
  392. End;
  393.  
  394. Begin
  395. End.
  396.